package uk.co.lunagroup.xmloperations;

import java.io.File;
import java.util.Date;
import java.util.Vector;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.poi.ss.usermodel.Row;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
 * . creates output BOM file
 * 
 * @author robert.kowalski
 * 
 */
public class WriteBomFile {

	/**
	 * . creates xml file from data set
	 * 
	 * @param rows
	 *            set of data from excel
	 */

	public static void writeBom(final Vector<Row> rows, final File file) {

		try {
			DocumentBuilderFactory bomFactory = DocumentBuilderFactory
					.newInstance();
			DocumentBuilder docBuilder = bomFactory.newDocumentBuilder();

			// root elements
			Document bomTable = docBuilder.newDocument();
			Element rootElement = bomTable.createElement("BOM");
			bomTable.appendChild(rootElement);

			// here insert parameters of the file

			// now set up configuration for creating the elements
			BomConfig configuration = new BomConfig();
			configuration.setDocument(bomTable);
			configuration.setDataSet(rows);

			// starting from row 2nd row (do not want to import title row) -
			// that is why i=1

			for (int i = 1; i < rows.size(); i++) {

				// creating row element and adding this to configuration
				Element rowElement = bomTable.createElement("row");

				// configure what is the same for the whole row so do not have
				// to call this later
				configuration.setParentElement(rowElement);
				configuration.setRowNr(i);

				// append row element to root
				rootElement.appendChild(rowElement);

				// add to configuration mappings of columns
				Vector<ElementColumnMapping> columns = mapColumnsWithNames();

				// here configure sets of columns
				for (int j = 0; j < columns.size(); j++) {
					configuration.setElementName(columns.elementAt(j)
							.getElementName());
					configuration.setColumnNr(columns.elementAt(j)
							.getColumnNr());
					// create element with current configuration
					writeElement(configuration);
				}

			}

			writeToFile(bomTable, file);

		} catch (ParserConfigurationException pce) {
			pce.printStackTrace();
		}
	}

	/**
	 * . updateds informations in fileList.xml file - adding XML path and modify
	 * date etc.
	 * 
	 * @param rows
	 *            Vector of FileList type data
	 * @param file
	 *            fileList.xml
	 */
	public static void updateFilesListXML(final Vector<FileList> rows,
			final File file) {

		try {
			DocumentBuilderFactory bomFactory = DocumentBuilderFactory
					.newInstance();
			DocumentBuilder docBuilder = bomFactory.newDocumentBuilder();

			// root elements
			Document doc = docBuilder.newDocument();
			Element rootElement = doc.createElement("filesToUpdate");
			doc.appendChild(rootElement);

			for (int i = 0; i < rows.size(); i++) {

				// creating row element and adding this to configuration
				Element rowElement = doc.createElement("file");
				// append row element to root
				rootElement.appendChild(rowElement);

				// create xlsPath
				Element xlsPath = doc.createElement("xlsPath");
				xlsPath.setTextContent(rows.get(i).getXlsFile().toString());
				rowElement.appendChild(xlsPath);

				// create xmlPath
				Element xmlPath = doc.createElement("xmlPath");
				xmlPath.setTextContent(rows.get(i).getXmlFile().toString());
				rowElement.appendChild(xmlPath);

				// create xmlServerPath
				Element xmlServerPath = doc.createElement("xmlServerPath");
				xmlServerPath
						.setTextContent(rows.get(i).getServerXmlFilePath());
				rowElement.appendChild(xmlServerPath);

				// create tender
				Element tender = doc.createElement("tender");
				tender.setTextContent(rows.get(i).getTender());
				rowElement.appendChild(tender);

				// create revision
				Element revision = doc.createElement("revision");
				revision.setTextContent(rows.get(i).getRevision());
				rowElement.appendChild(revision);

				// create tenderName
				Element tenderName = doc.createElement("tenderName");
				tenderName.setTextContent(rows.get(i).getTenderName());
				rowElement.appendChild(tenderName);

				// created and update modify date of XLS file, not generating
				// XML file
				Element modifyDate = doc.createElement("modifyDate");
				Date lastModified = new Date(rows.get(i).getXlsFile()
						.lastModified());
				modifyDate.setTextContent(lastModified.toString());
				rowElement.appendChild(modifyDate);

				// created and update modify date of XML file
				Element xmlFileGenreateDate = doc
						.createElement("XMLFileGenerated");
				new Date(rows.get(i).getXmlFile().lastModified());
				xmlFileGenreateDate.setTextContent(lastModified.toString());
				rowElement.appendChild(xmlFileGenreateDate);

			}

			writeToFile(doc, file);

		} catch (ParserConfigurationException pce) {
			pce.printStackTrace();
		}
	}

	/**
	 * . writes element to xml document
	 * 
	 * @param configuration
	 *            Configuration class is holding parameters to map BOM table
	 * 
	 */
	public static void writeElement(final BomConfig configuration) {
		Document doc = configuration.getDocument();
		Vector<Row> data = configuration.getDataSet();
		Element parentElement = configuration.getParentElement();
		int rowNr = configuration.getRowNr();
		int columnNr = configuration.getColumnNr();
		String elementName = configuration.getElementName();

		Element element = doc.createElement(elementName);

		// check if cell is not null and then copy data to xml. Else set value
		// for "null" - marker that value of cell was null
		if (data.get(rowNr).getCell(columnNr) != null) {
			element.appendChild(doc.createTextNode(data.get(rowNr)
					.getCell(columnNr).toString()));
			parentElement.appendChild(element);
		} else {
			element.appendChild(doc.createTextNode("null"));
			parentElement.appendChild(element);

		}
	}

	/**
	 * . writes document into xml file
	 * 
	 * @param document
	 *            document to write
	 */
	public static void writeToFile(final Document document, final File file) {
		// write the content into xml file
		try {
			TransformerFactory transformerFactory = TransformerFactory
					.newInstance();
			Transformer transformer;

			transformer = transformerFactory.newTransformer();

			// set some options on the transformer. makes document look nice
			transformer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
			transformer
					.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
			transformer.setOutputProperty(OutputKeys.INDENT, "yes");
			transformer.setOutputProperty(
					"{http://xml.apache.org/xslt}indent-amount", "2");

			DOMSource source = new DOMSource(document);

			// here call later procedure to choose file name
			StreamResult result = new StreamResult(file);

			// Output to console for testing
			// StreamResult result = new StreamResult(System.out);

			transformer.transform(source, result);

			System.out.println("File saved!" + file.getAbsolutePath());

		} catch (TransformerException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/**
	 * . writes document into xml file
	 * 
	 * @param document
	 *            document to write
	 */

	/**
	 * . keeps pair parameters - column name and column nr.
	 * 
	 * @return vector of pairs (pairs as ElementColumnMapping class)
	 */
	public static Vector<ElementColumnMapping> mapColumnsWithNames() {
		Vector<ElementColumnMapping> pairs = new Vector<ElementColumnMapping>();
		ElementColumnMapping setOfPairs = new ElementColumnMapping();

		setOfPairs.setElementName("ConditionNr");
		setOfPairs.setColumnNr(0);
		pairs.addElement(new ElementColumnMapping(setOfPairs));

		setOfPairs.setElementName("ConditionName");
		setOfPairs.setColumnNr(1);
		pairs.addElement(new ElementColumnMapping(setOfPairs));

		setOfPairs.setElementName("Height");
		setOfPairs.setColumnNr(2);
		pairs.addElement(new ElementColumnMapping(setOfPairs));

		setOfPairs.setElementName("TakeOffQty");
		setOfPairs.setColumnNr(4);
		pairs.addElement(new ElementColumnMapping(setOfPairs));

		setOfPairs.setElementName("UOM1");
		setOfPairs.setColumnNr(5);
		pairs.addElement(new ElementColumnMapping(setOfPairs));

		setOfPairs.setElementName("Floor");
		setOfPairs.setColumnNr(12);
		pairs.addElement(new ElementColumnMapping(setOfPairs));

		setOfPairs.setElementName("Plot");
		setOfPairs.setColumnNr(13);
		pairs.addElement(new ElementColumnMapping(setOfPairs));

		setOfPairs.setElementName("NormNr");
		setOfPairs.setColumnNr(14);
		pairs.addElement(new ElementColumnMapping(setOfPairs));

		setOfPairs.setElementName("NormName");
		setOfPairs.setColumnNr(15);
		pairs.addElement(new ElementColumnMapping(setOfPairs));

		setOfPairs.setElementName("Ratio");
		setOfPairs.setColumnNr(16);
		pairs.addElement(new ElementColumnMapping(setOfPairs));

		setOfPairs.setElementName("SKU");
		setOfPairs.setColumnNr(17);
		pairs.addElement(new ElementColumnMapping(setOfPairs));

		setOfPairs.setElementName("Category");
		setOfPairs.setColumnNr(18);
		pairs.addElement(new ElementColumnMapping(setOfPairs));

		setOfPairs.setElementName("Description");
		setOfPairs.setColumnNr(19);
		pairs.addElement(new ElementColumnMapping(setOfPairs));

		setOfPairs.setElementName("Qty");
		setOfPairs.setColumnNr(21);
		pairs.addElement(new ElementColumnMapping(setOfPairs));

		setOfPairs.setElementName("Unit");
		setOfPairs.setColumnNr(22);
		pairs.addElement(new ElementColumnMapping(setOfPairs));

		setOfPairs.setElementName("Rate");
		setOfPairs.setColumnNr(23);
		pairs.addElement(new ElementColumnMapping(setOfPairs));

		setOfPairs.setElementName("Total");
		setOfPairs.setColumnNr(24);
		pairs.addElement(new ElementColumnMapping(setOfPairs));

		setOfPairs.setElementName("NormUnit");
		setOfPairs.setColumnNr(25);
		pairs.addElement(new ElementColumnMapping(setOfPairs));

		setOfPairs.setElementName("VladarUnits");
		setOfPairs.setColumnNr(26);
		pairs.addElement(new ElementColumnMapping(setOfPairs));

		setOfPairs.setElementName("QtyPerPlot");
		setOfPairs.setColumnNr(27);
		pairs.addElement(new ElementColumnMapping(setOfPairs));

		setOfPairs.setElementName("ValuePerPlot");
		setOfPairs.setColumnNr(28);
		pairs.addElement(new ElementColumnMapping(setOfPairs));

		setOfPairs.setElementName("Package");
		setOfPairs.setColumnNr(29);
		pairs.addElement(new ElementColumnMapping(setOfPairs));

		setOfPairs.setElementName("FixPackage");
		setOfPairs.setColumnNr(30);
		pairs.addElement(new ElementColumnMapping(setOfPairs));

		setOfPairs.setElementName("MaterialCategory");
		setOfPairs.setColumnNr(31);
		pairs.addElement(new ElementColumnMapping(setOfPairs));

		return pairs;

	}

}